#if defined(CurveClipping) && (defined(GLES2Platform) || !defined(CurveClippingAllowed))
  // Disable sectioning for mobile and some passes (like mirroring)
  #undef CurveClipping
#endif

#ifdef CurveClipping

  //uniform samplerBuffer curveClippingData;

  void PerformCurveClippingDiscard()
  {
    // Structure of the TBO:
    // 1st vec4: buffer status, curve count, padding, padding

    // 1st curve data info:
    // 2nd vec4: curve id, vertex count, max projected distance, start of vertex list clipping planes
    // 3rd vec4: curve clipping direction + flag to determine if this is the first part of a multiple curves
    // 4th vec4: 1st vertex position in view space + flag to determine if this is the last part of a multiple curves
    // 5th vec4: list of vertices projected distances to the first vertex
    // nth vec4: clipping planes list

    // 2nd curve data info:
    // same structure as first curve info

    vec4 v0 = vTexelFetch(curveClippingData, 0);
    int curveCount = int(v0.y); 

    int nextCurve = 0;
    int previousClippingPlaneListOffset = 1; // set 1 here to get the 1st curve index correct
    int previousVertexCount = 0;

    vec3 fragPos = vGetViewPosition();
    
    int i, j, k;

    // Number of curves applied to this fragment with same ID
    int fragCurveCount = 0;

    // Increment this counter when the clipping plane for one curve discards the fragement
    int fragDiscardCount = 0;
    
    // Use case for reversing the normal on the Smedi bridge
    // Detect fragments between two consecutive curves which are not clipped by the first curve because
    // being out of bounds, but which would be clipped if no bounds checking, and also not clipped by the
    // following curve because out of bounds, but which would be clipped too whitout bounds checking
    int inBetweenCounter = 0;
    int inBetweenDiscardCount = 0;

    for(k = 0; k < curveCount; k++)
    {
       // Next curve index
       nextCurve = previousClippingPlaneListOffset + previousVertexCount;

       vec4 curveData = vTexelFetch(curveClippingData, nextCurve);
       
       // Get curve info
       int curveID = int(curveData.x);
       int vertexCount = int(curveData.y);
       float maxProjectedDistance = curveData.z;
       int projectedDistanceListOffset = nextCurve + 3;
       int clippingPlaneListOffset = int(curveData.w);
       
       // Update for next curve
       previousVertexCount = vertexCount;
       previousClippingPlaneListOffset = clippingPlaneListOffset;

       // Check if this curve is applied to this fragment
       if((_sbCurveClipping.u_CurveClippingIDs & curveID) == 0)
       {
         fragCurveCount = 0;
         fragDiscardCount = 0;
         inBetweenCounter = 0;
         continue;
       }

       // Check if a clipping plane is found for this fragment
       int valid = 0;
       vec4 clippingPlane;

       // Get curve info
       vec4 ccDirData = vTexelFetch(curveClippingData, nextCurve + 1);
       vec3 ccDir = ccDirData.xyz;
       float isFirstCurve = ccDirData.w;

       vec4 p0Data = vTexelFetch(curveClippingData, nextCurve + 2);
       vec3 p0 = p0Data.xyz;
       float isLastCurve = p0Data.w;
       
       // Compute projected distance to the first vertex
       float projectedDistance = vDot(fragPos - p0, ccDir);

       // Reset the in-between fragment counters after detecting two successive curves
       inBetweenCounter = inBetweenCounter == 2 ? 0 : inBetweenCounter;
       inBetweenDiscardCount = inBetweenCounter == 0 ? 0 : inBetweenDiscardCount;

       // Update the curve counter for current fragment between two curves applied to it
       ++inBetweenCounter;

       // 1st vertex projected distance is 0
       if(projectedDistance < 0.0)
       {
         // Only clip fragments with negative projected distances for the first curve
         clippingPlane = vTexelFetch(curveClippingData, clippingPlaneListOffset);
         if(isFirstCurve > 0.0)
         {
           // New curve found
           fragCurveCount++;
           valid = 1;
         }

         // This is the second curve and the fragment is out of bounds
         if((inBetweenCounter == 2) && (vDot(vec4(fragPos, 1.0), clippingPlane)) <= 0.0)
         {
            // Increment the discard count because it would be clipped without bounds checking
           ++inBetweenDiscardCount;
         }
       }
       else if(projectedDistance > maxProjectedDistance)
       {
         // Only clip fragments with projected distances greater than the max distance for the last curve
         clippingPlane = vTexelFetch(curveClippingData, vertexCount + clippingPlaneListOffset - 1);

         if(isLastCurve > 0.0)
         {
          // New curve found
          fragCurveCount++;
          valid = 1;
         }

         // This is the first curve and the fragment is out of bounds
         if((inBetweenCounter == 1) && (vDot(vec4(fragPos, 1.0), clippingPlane)) <= 0.0)
         {
           // Increment the discard count if it would be clipped without bounds checking
           ++inBetweenDiscardCount;
         }
       }
       else
       {
         int previousIndex = vertexCount;
       
         // Find the interval which contains the fragment projected distance
         for(i = 0, j = 0; i < vertexCount; i += 4, j++)
         {
           vec4 distances = vTexelFetch(curveClippingData, j + projectedDistanceListOffset);
       
           if((distances.x > projectedDistance) && (i + 0 < vertexCount))  // 1st vertex
           { 
             previousIndex = i - 1 > 0 ? i - 1 : 0;
             break;
           }
           else if((distances.y > projectedDistance) && (i + 1 < vertexCount))// 2nd vertex
           {
             previousIndex = i + 0;
             break;
           }
           else if((distances.z > projectedDistance) && (i + 2 < vertexCount)) // 3rd vertex
           {
             previousIndex = i + 1;
             break;
           }
           else if((distances.w > projectedDistance) && (i + 3 < vertexCount)) // 4th vertex
           {
             previousIndex = i + 2;
             break;
           }
         }
         
         // Find the clipping plane
         if(previousIndex < vertexCount)
         {
           clippingPlane = vTexelFetch(curveClippingData, clippingPlaneListOffset + previousIndex);

           // New curve found
           fragCurveCount++;
           valid = 1;
         }

        } // else

        // Increment the discard counter if the fragment is clipped
        if((valid > 0) && (vDot(vec4(fragPos, 1.0), clippingPlane) <= 0.0))
        {
          fragDiscardCount++;
        }

        // Check if the fragemnt is discarded because the last curve is detected
        if(isLastCurve > 0.0)
        {
          // Only clip the fragment if it has been clipped by all curves applied to this fragment
          if((fragCurveCount > 0) && (fragCurveCount == fragDiscardCount))
          {
            discard;
          }
          
          // Reset the counters for the next curve
          fragCurveCount = fragDiscardCount = 0;
        }

        // Only discard if the counters match after detecting two successive curves
        if(inBetweenCounter == 2 && inBetweenDiscardCount == 2)
        {
           discard;
        }

    } // Next curve
  }

#endif
